package com.rq.base.net;

import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;


import com.rq.base.BASE;
import com.rq.base.net.impl.HttpInnerListener;
import com.rq.base.util.GsonUtil;
import com.rq.base.util.LOG;
import com.rq.base.util.SPUtil;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HttpsURLConnection;

import static com.rq.base.net.HttpSender.getRequestData;

public class HttpThreadManager {

    public interface OnListener extends HttpInnerListener {
        void onOver();
    }

    public interface UploadListener extends HttpInnerListener {

    }

    public interface DownListener {
        void onProgress(int progress, int allLength);

        void onCompleted(File file);

        void onError(String msg);
    }

    private static Set<String> debugNotRecorder = new HashSet<>();

    public void removeRecorder(String... watchs) {
        debugNotRecorder.addAll(Arrays.asList(watchs));
    }

    private static HttpThreadManager model = new HttpThreadManager();

    private HttpThreadManager() {
    }

    // 获得单例对象
    public static HttpThreadManager get() {
        return model;
    }

    private static Handler main = new Handler(Looper.getMainLooper());
    //    private static HashMap<String, ExecutorService> postPool = new HashMap<>();


    void download(String httpUrl, final Map<String, Object> params,
                  final String filePathAndName, final DownListener out) {
        final Handler main = new Handler(Looper.getMainLooper());
        long oldLength = 0;
        //下载文件的名字
        final File file = new File(filePathAndName);
        LOG.e("HttpThreadManager", "run.129:" + filePathAndName);
        try {
            String dirPath =
                    filePathAndName.substring(0, filePathAndName.lastIndexOf("/"));
            if (!new File(dirPath).exists()) {
                new File(dirPath).mkdirs();
            }
            if (file.exists()) {
                oldLength = file.length();
//                file.delete();
            } else {
                file.createNewFile();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }


        //下载文件的路径
        String stringBuffer = getRequestData(NET_PARAM_HELPER.getParam(params), "UTF-8").toString();
        if (!TextUtils.isEmpty(stringBuffer)) {
            httpUrl = httpUrl + "?" + stringBuffer;
        }
        final DownListener listener = new DownListener() {
            @Override
            public void onProgress(final int progress, final int all) {
                if (out != null) {
                    main.post(new Runnable() {
                        @Override
                        public void run() {
                            out.onProgress(progress, all);
                        }
                    });
                }
            }

            @Override
            public void onCompleted(final File file) {
                if (out != null) {
                    main.post(new Runnable() {
                        @Override
                        public void run() {
                            out.onCompleted(file);
                        }
                    });
                }
            }

            @Override
            public void onError(final String msg) {
                if (out != null) {
                    main.post(new Runnable() {
                        @Override
                        public void run() {
                            out.onError(msg);
                        }
                    });
                }
            }
        };
        final String finalHttpUrl = httpUrl;
        ThreadFactory namedThreadFactory = new ThreadFactoryBuilder("demo-pool-%d");

        ExecutorService pool = new ThreadPoolExecutor(5, 200, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
        long startLength = oldLength;
        pool.execute(new Runnable() {
            @Override
            public void run() {

                InputStream is = null;
                RandomAccessFile fos = null;
                try {
                    URL url = new URL(finalHttpUrl);
                    Log.e("", "downLoad state = " + finalHttpUrl);
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    int fileLength;
                    Log.i("HttpThreadManager", "startLength = " + startLength);
                    if (startLength > 0) {
                        fileLength = SPUtil.getInt(finalHttpUrl);//conn.getContentLength();
                        LOG.e("HttpThreadManager", "fileLength:" + fileLength);
                        if (startLength >= fileLength) {
                            listener.onCompleted(file);
                            return;
                        }
                        conn.setRequestProperty("RANGE", "bytes=" + startLength + "-" + fileLength);
                    } else {
                        fileLength = conn.getContentLength();//conn.getContentLength();
                        LOG.e("HttpThreadManager", "fileLength.save:" + fileLength);
                        SPUtil.saveInt(finalHttpUrl, fileLength);
                    }

                    conn.setConnectTimeout(60000);//jdk 1.5换成这个,连接超时
                    conn.setReadTimeout(60000);//jdk 1.5换成这个,读操作超时
                    System.setProperty("https.protocols", "TLSv1.2");
                    is = conn.getInputStream();
                    fos = new RandomAccessFile(file, "rwd");
                    if (startLength > 0) {
                        fos.seek(startLength);
                    }
                    byte[] buf = new byte[256];
                    Log.i("HttpThreadManager", "downLoad connect OK !is downloading now");
                    if (conn.getResponseCode() >= 400) {
                        listener.onError("接口连接错误：" + conn.getResponseCode());
                        Log.i("HttpThreadManager", "getResponseCode = " + conn.getResponseCode());
                    } else {
                        int downLoad_num = (int) startLength;
                        int b = 0;
                        while ((b = is.read(buf)) != -1) {
                            fos.write(buf, 0, b);
                            downLoad_num += b;
                            if (downLoad_num != fileLength) {
                                listener.onProgress(downLoad_num, fileLength);
                            } else {
                                listener.onCompleted(file);
                            }
                        }
                    }
                    conn.disconnect();
                } catch (Exception e) {
                    e.printStackTrace();
                    listener.onError(e.getMessage());
                } finally {
                    if (fos != null) {
                        try {
                            fos.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                            listener.onError(e.getMessage());
                        }
                    }
                    if (is != null) {
                        try {
                            is.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                            listener.onError(e.getMessage());
                        }
                    }
                }
            }
        });
    }

    private static final String POST_TYPE_1 = "application/x-www-form-urlencoded";//键值对传参
    private static final String POST_TYPE_2 = "multipart/form-data";              //既可以上传键值对也可以上传文件 可上传多个文件
    private static final String POST_TYPE_3 = "application/json";                 //上传JSON格式的数据

    public static String POST_TYPE = POST_TYPE_3;

    private String makePostData(Map<String, Object> params) {
        if (POST_TYPE == POST_TYPE_1) {
            return getRequestData(NET_PARAM_HELPER.getParam(params), "UTF-8").toString();
        }
        if (POST_TYPE == POST_TYPE_3) {
            return GsonUtil.toJson(params);
        }
        return "";
    }

    public void upload(final String path, File file, Map<String, String> heads, final Map<String, Object> params, final OnListener listener) {

    }

//    public void send(final String path, String way, Map<String, String> heads, final Map<String, Object> params, final OnListener listener) {
//        send(path, null, way, heads, params, listener);
//    }

    public void upload(String path, List<File> fileList, Map<String, String> heads, Map<String, Object> params, UploadListener listener) {
      ThreadFactory namedThreadFactory = new ThreadFactoryBuilder("demo-pool-%d");
        ExecutorService pool = new ThreadPoolExecutor(5, 200, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
        pool.execute(new Runnable() {
            @Override
            public void run() {
                String resultCode = "";
                String end = "\r\n";
                String twoHyphens = "--";
                String boundary = "--------boundary";

                try {
                    URL url = new URL(path);
                    HttpURLConnection con = (HttpURLConnection) url.openConnection();
                    if (heads != null && heads.size() > 0) {
                        for (String key : heads.keySet()) {
                            con.setRequestProperty(key, heads.get(key));
                        }
                    }
                    // 允许Input、Output，不使用Cache
                    con.setDoInput(true);
                    con.setDoOutput(true);
                    con.setUseCaches(false);
                    // 设置传送的method=POST
                    con.setRequestMethod("POST");
                    // setRequestProperty
                    con.setRequestProperty("Connection", "Keep-Alive");
                    con.setRequestProperty("Charset", "UTF-8");
                    // con.setRequestProperty("Content-Type",
                    // "application/x-www-form-urlencoded");
                    con.setRequestProperty("Content-Type", POST_TYPE_2+";boundary=" + boundary);
                    // 设置DataOutputStream
                    DataOutputStream dos = new DataOutputStream(con.getOutputStream());
                    for (int i = 0; i < fileList.size(); i++) {
                        File file = fileList.get(i);
                        String filePath = file.getPath();
                        int endFileIndex = filePath.lastIndexOf("/");
                        String fileName = filePath.substring(endFileIndex + 1);
                        Log.i("HttpThreadManager", "filename= " + fileName);
                        // set 头部
                        StringBuilder sb = new StringBuilder();
                        sb.append(twoHyphens);
                        sb.append(boundary);
                        sb.append(end);
                        sb.append("Content-Disposition: form-data; ");
                        sb.append("name=" + "\"" + "upload_file" + i + "\"");
                        sb.append(";filename=");
                        sb.append("\"" + fileName + "\"");
                        sb.append(end);
                        sb.append("Content-Type: ");
                        sb.append(getMIMEType(file));
                        sb.append(end);
                        sb.append(end);
                        // 1. write sb
                        dos.writeBytes(sb.toString());
                        // 取得文件的FileInputStream
                        FileInputStream fis = new FileInputStream(filePath);
                        // 设置每次写入1024bytes
                        int bufferSize = 1024;
                        byte[] buffer = new byte[bufferSize];
                        int length = -1;
                        // 从文件读取数据至缓冲区
                        while ((length = fis.read(buffer)) != -1) {
                            dos.write(buffer, 0, length);
                        }
                        dos.writeBytes(end);
                        fis.close();
                        dos.writeBytes(end);
                        dos.writeBytes(end);
                        //dos.writeBytes(end);
                        //dos.flush();
                        // close streams
                        //fis.close();
                    }
                    // set 尾部
                    StringBuilder sb2 = new StringBuilder();
                    if (params != null && !params.isEmpty()) {
                        for (String key : params.keySet()) {
                            String value = String.valueOf(params.get(key));
                            sb2.append(twoHyphens);
                            sb2.append(boundary);
                            sb2.append(end);
                            sb2.append("Content-Disposition: form-data; ");
                            sb2.append("name=" + "\"");
                            sb2.append(key + "\"");
                            sb2.append(end);
                            sb2.append(end);
                            sb2.append(value);
                            sb2.append(end);
                        }
                    }
                    sb2.append(twoHyphens + boundary + end);
                    dos.writeBytes(sb2.toString());
                    dos.flush();
                    Log.i("HttpThreadManager", "sb2:" + sb2.toString());
                    // 取得Response内容
                    InputStream is = con.getInputStream();
                    int ch;
                    StringBuffer b = new StringBuffer();
                    while ((ch = is.read()) != -1) {
                        b.append((char) ch);
                    }
                    resultCode = b.toString().trim();
                    // 关闭
                    dos.close();
                } catch (IOException e) {
                    Log.i("HttpThreadManager", "IOException: " + e);
                    e.printStackTrace();
                } finally {
                    LOG.e("HttpThreadManager", "resultCode:" + resultCode);
                }
            }
        });

    }

    private String getMIMEType(File file) {
        String fileName = file.getName();
        if (fileName.endsWith("png") || fileName.endsWith("PNG")) {
            return "image/png";
        } else {
            return "image/jpg";
        }
    }

    public void send(final String path, String way, Map<String, String> heads, final Map<String, Object> params, final OnListener listener) {
        final String tag = path.substring(path.lastIndexOf("/") + 1);
        //    final long NetStartTime = System.currentTimeMillis();
        //    ThreadFactory namedThreadFactory = new ThreadFactoryBuilder("demo-pool-%d");
        //    ExecutorService pool = new ThreadPoolExecutor(3, 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
        ThreadFactory namedThreadFactory = new ThreadFactoryBuilder("demo-pool-%d");
        LOG.e("HttpThreadManager", "way:" + way);
        ExecutorService pool = new ThreadPoolExecutor(5, 200, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
        pool.execute(new Runnable() {
            //    Executors.newCachedThreadPool().execute(new Runnable() {
            @Override
            public void run() {
//                String pathAll = path + "?" + stringBuffer;
//                LOG.d("ThreadManager", Thread.currentThread().getName() + ".run.93:" + pathAll);
                InputStream inputStream = null;
                OutputStream outputStream = null;
                HttpURLConnection httpURLConnection = null;
                long startTime = System.currentTimeMillis();
                try {
                    URL url = new URL(path);
                    if (path.startsWith("https")) {
                        httpURLConnection = (HttpsURLConnection) url.openConnection();
                    } else {
                        httpURLConnection = (HttpURLConnection) url.openConnection();
                    }
                    if (heads != null && heads.size() > 0) {
                        for (String key : heads.keySet()) {
                            httpURLConnection.setRequestProperty(key, heads.get(key));
                        }
                    }
                    if ("GET".equals(way)) {
                        httpURLConnection.setRequestMethod("GET");//请求方式
                        httpURLConnection.setConnectTimeout(8000);//连接最大时间
                        httpURLConnection.setReadTimeout(8000);//读取最大时间
                    } else {
                        httpURLConnection.setConnectTimeout(20_000);                        //设置连接超时时间
                        httpURLConnection.setReadTimeout(20_000);                           //设置连接超时时间
                        httpURLConnection.setDoInput("POST".equals(way));                   //打开输入流，以便从服务器获取数据
                        httpURLConnection.setDoOutput("POST".equals(way));                  //打开输出流，以便向服务器提交数据
                        httpURLConnection.setRequestMethod(way);                            //设置以Post方式提交数据
                        httpURLConnection.setUseCaches(false);                              //使用Post方式不能使用缓存
                        //必须设置false，否则会自动redirect到重定向后的地址
                        httpURLConnection.setInstanceFollowRedirects(false);
//                        if (POST_TYPE_2.equals(POST_TYPE) && file != null) {
//                            String BOUNDARY = UUID.randomUUID().toString();  //边界标识   随机生成
//                            httpURLConnection.setRequestProperty("Charset", "utf-8");  //设置编码
//                            httpURLConnection.setRequestProperty("connection", "keep-alive");
//                            httpURLConnection.setRequestProperty("Content-Type", POST_TYPE_2 + ";boundary=" + BOUNDARY);
//                            sendWithFile(httpURLConnection, file, BOUNDARY);
//                        } else {
                        //设置请求体的类型是文本类型
                        httpURLConnection.setRequestProperty("Content-Type", POST_TYPE);

                        String stringBuffer = makePostData(params);
                        LOG.e("HttpThreadManager", "271:" + stringBuffer);
                        byte[] data = stringBuffer.getBytes();//获得请求体
                        //设置请求体的长度
                        httpURLConnection.setRequestProperty("Content-Length", String.valueOf(data.length));
                        if ("POST".equals(way)) {
                            //获得输出流，向服务器写入数据
                            outputStream = httpURLConnection.getOutputStream();
                            outputStream.write(data);
                        }
//                        }
                    }
                    //获得服务器的响应码
                    final int response = httpURLConnection.getResponseCode();

                    //          try {
                    //            LOG.e("HttpThreadManager", "run.95:");
                    //            Thread.sleep(1);
                    //          } catch (InterruptedException e) {
                    //            e.printStackTrace();
                    //          }
                    //          LOG.e("HttpThreadManager", "run.100:");
                    LOG.e("HttpThreadManager", "265:" + response);
                    if (response == HttpURLConnection.HTTP_OK) {
                        inputStream = httpURLConnection.getInputStream();
                        String resultData = null;      //存储处理结果
                        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                        byte[] d = new byte[1024];
                        int len = 0;
                        try {
                            while ((len = inputStream.read(d)) != -1) {
                                byteArrayOutputStream.write(d, 0, len);
                            }
                        } catch (IOException e) {
                            main.post(new Runnable() {
                                @Override
                                public void run() {
                                    if (listener != null)
                                        listener.onEmptyResponse("[" + tag + "]HttpCode:" + response);
                                }
                            });
                            return;
                        }
                        resultData = new String(byteArrayOutputStream.toByteArray());
                        LOG.e("HttpThreadManager", tag + "--run.105-->:" + resultData);
                        if ("Pay".equals(tag) && TextUtils.isEmpty(resultData)) {
                            main.post(new Runnable() {
                                @Override
                                public void run() {
                                    if (listener != null) listener.onString(null);
                                }
                            });
                            return;
                        }
                        final String finalResultData = resultData;
                        main.post(new Runnable() {
                            @Override
                            public void run() {
                                if (listener != null) listener.onString(finalResultData);
                            }
                        });
                        recoder(path, startTime, finalResultData, params);
                    } else {
                        LOG.d("ThreadManager", path + ".请求异常:" + response);
                        main.post(new Runnable() {
                            @Override
                            public void run() {
                                if (listener != null)
                                    listener.onEmptyResponse("[" + tag + "]HttpCode:" + response);
                            }
                        });
                        recoder(path, startTime, "[" + tag + "]HttpCode:" + response, params);
                    }
                } catch (final Exception e) {
                    e.printStackTrace();
                    main.post(new Runnable() {
                        @Override
                        public void run() {
                            if (listener != null) listener
                                    .onEmptyResponse("[" + tag + "]" + e.getClass().getSimpleName() + ":" + e
                                            .getMessage());
                        }
                    });
                    recoder(path, startTime, "[" + tag + "]" + e.getClass().getSimpleName() + ":" + e
                            .getMessage(), params);
                } finally {
                    LOG.e("HttpThreadManager", tag + ".消耗时间:" + (System.currentTimeMillis() - startTime));
                    if (listener != null) listener.onOver();
                    if (httpURLConnection != null) httpURLConnection.disconnect();
                    if (inputStream != null) {
                        try {
                            inputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (outputStream != null) {
                        try {
                            outputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    //          postPool.remove(path);
                }
            }
        });
        //    LOG.e("HttpThreadManager", "run.postPool.add:" + pool.hashCode());
        //    postPool.open(path, pool);
        pool.shutdown();//gracefully shutdown
        LOG.e("HttpThreadManager", "add.182:" + path);
    }

    private void sendWithFile(HttpURLConnection conn, File file, String BOUNDARY) throws IOException {
        String PREFIX = "--", LINE_END = "\r\n";
        /**
         * 当文件不为空，把文件包装并且上传
         */
        OutputStream outputSteam = conn.getOutputStream();

        DataOutputStream dos = new DataOutputStream(outputSteam);
        StringBuffer sb = new StringBuffer();
        sb.append(PREFIX);
        sb.append(BOUNDARY);
        sb.append(LINE_END);
        /**
         * 这里重点注意：
         * name里面的值为服务器端需要key   只有这个key 才可以得到对应的文件
         * filename是文件的名字，包含后缀名的   比如:abc.png
         */

        sb.append("Content-Disposition: form-data; name=\"img\"; filename=\"" + file.getName() + "\"" + LINE_END);
        sb.append("Content-Type: application/octet-stream; charset=utf-8" + LINE_END);
        sb.append(LINE_END);
        dos.write(sb.toString().getBytes());
        InputStream is = new FileInputStream(file);
        byte[] bytes = new byte[1024];
        int len = 0;
        while ((len = is.read(bytes)) != -1) {
            dos.write(bytes, 0, len);
        }
        is.close();
        dos.write(LINE_END.getBytes());
        byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINE_END).getBytes();
        dos.write(end_data);
        dos.flush();
    }

    public void recoder(String pathAll, long startTime, String finalResultData,
                        Map<String, Object> params) {
        //    if (debugNotRecorder.contains(pathAll) || !BuildConfig.LOG_DEBUG) return;
        //    CrashHandler.getInstance()
        //                .saveNETResponseInfo(pathAll, params, finalResultData, startTime, System
        //                    .currentTimeMillis());
    }


    public void cancelNet(String path) {
        //    ExecutorService post = postPool.get(path);
        //    LOG.e("HttpThreadManager", "run.postPool.Thread:" + post.hashCode());
        //    LOG.e("HttpThreadManager", "cancelNet.182:disconnect." + path);
        //    post.shutdownNow();
    }
}
